/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package compilador.tabelaDeSimbolos;

import compilador.analisadorSintatico.simboloGramatical.NaoTerminal;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Henrique
 */
public class TabelaSimbolos {

    private static TabelaSimbolos instance;
    
    private static boolean DEBUG = true;
    
    public static TabelaSimbolos getInstance(){
        if(instance == null){
            createInstance();
        }
        
        return instance;
    }

    public static void createInstance() {
        instance = new TabelaSimbolos();
    }
    
    public static String print(){
        StringBuilder stBuild = new StringBuilder();
        
        stBuild.append("\n\n Tabela de Símbolos\n");
        stBuild.append("Nome  " + " " + "Tipo  " + " " + "Escopo   \n") ;
        for(String key: instance.simbolos.keySet()){
            Identificador id = instance.simbolos.get(key);
            stBuild.append(id.getNome() + " " + id.getTipo() + " " + id.getEscopo().getNome() + "@" + id.getEscopo().hashCode() + "\n") ;
        }
        stBuild.append("=========================================") ;
        System.out.print(stBuild.toString());
        
        return stBuild.toString();
    }
    
    private HashMap<String, Identificador> simbolos;
    
    private TabelaSimbolos() {
        this.simbolos = new HashMap<String, Identificador>();
    }
    
    public void insert(Identificador id) throws InsertException{
        String chave = "";
        
        if(id.getEscopo() != null && id.getTipo() != null){
            chave = generateKey(id.getNome(), id.getEscopo());
            if(! this.simbolos.containsKey(chave)){
                this.simbolos.put(chave, id);
            }else{
                throw new InsertException(id);
            }
        
        }else{
            throw new InsertException(id, "Tipo ou Escopo do identificador não encontrado");
        }
    }

    public void insert(Identificador id, String tipo, NaoTerminal escopo) throws InsertException{
        id.setTipo(tipo);
        id.setEscopo(escopo);
        
        insert(id);
    }
    
    public void insert(String nome, String tipo, NaoTerminal escopo) throws InsertException{
        Identificador id = new Identificador(nome);
        id.setTipo(tipo);
        id.setEscopo(escopo);
        
        insert(id);
    }
    
    public Identificador get(String nome, NaoTerminal escopo){
        String chave = generateKey(nome, escopo);
        
        return this.simbolos.get(chave);
    }
    
    public boolean containsKey(String nome, NaoTerminal escopo) {
        String chave = generateKey(nome, escopo);
        
        return this.simbolos.containsKey(chave);
    }
    
    
    private String generateKey(String nome, NaoTerminal escopo){
        String key = nome + "$" + escopo.hashCode();
        
        if(TabelaSimbolos.DEBUG)
            System.out.println(key);
        
        return key;
    }
    
    public static void main(String arg[]){
        final NaoTerminal naoTerminal = new NaoTerminal("SemEscopo");
        Identificador id = new Identificador("SemNome", "SemTipo",naoTerminal);
        
        try {
            TabelaSimbolos.getInstance().insert(id);
            
            TabelaSimbolos.getInstance().insert("SemNome", "SemTipo", null);
        } catch (InsertException ex) {
            Logger.getLogger(TabelaSimbolos.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
    }

}
